package kq

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/mqueuex"
	"mall/common/utils/pointy"
	"mall/service/backend/common/deepseek"
	"mall/service/backend/common/websocket"
	"mall/service/backend/rmq/internal/svc"
	"mall/service/forum/rpc/forumclient"

	"github.com/friendsofgo/errors"
	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type DeferredInquireAiMq struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewDeferredInquireAiMq(ctx context.Context, svcCtx *svc.ServiceContext) *DeferredInquireAiMq {
	return &DeferredInquireAiMq{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *DeferredInquireAiMq) Consume(_, val string) error {
	// 解析数据
	var message mqueuex.DeferredInquireAIMessage
	if err := json.Unmarshal([]byte(val), &message); err != nil {
		logx.Errorw("DeferredInquireAiMq.Consume json.Unmarshal err", logx.Field("detail", err.Error()))
		return err
	}

	// logrus.Info(fmt.Sprintf("DeferredInquireAiMq message: %+v", message))

	// 执行业务..
	if err := l.execService(&message); err != nil {
		logx.Errorw("DeferredInquireAiMq.execService err", logx.Field("detail", err.Error()),
			logx.Field("val", val), logx.Field("message", fmt.Sprintf("%+v", message)))
		return err
	}

	return nil
}

func (l *DeferredInquireAiMq) execService(message *mqueuex.DeferredInquireAIMessage) error {
	if message.UserId == nil || message.TopicId == nil {
		return errors.New(fmt.Sprintf("DeferredInquireAiMq.execService err, invalid param: %+v", message))
	}

	preload := "forumPost:Id,ContentHtml"
	var filters []string
	filters = append(filters, "TopicId,equalTo:"+strconv.FormatUint(*message.TopicId, 10))
	filters = append(filters, "ForumId,equalTo:"+strconv.FormatInt(l.svcCtx.Config.Query.DSForumId, 10))
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusDraft), 10))
	sorter := "Id"

	res, err := l.svcCtx.ForumRpc.GetPostList(l.ctx, &forumclient.BaseListReq{
		Preload:    pointy.GetPointer(preload),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:     pointy.GetPointer(sorter),
		VisitorId:  message.UserId,
		PlatformId: pointy.GetPointer(globalkey.ThirdPartyPlatformWechatMini),
	})
	if err != nil {
		logx.Infow("DeferredInquireAiMq.execService GetPostList err", logx.Field("detail", err.Error()))
		return err
	}

	if len(res.List) > 0 {
		var contents []string
		for _, v := range res.List {
			if v.PostContent != nil {
				contents = append(contents, *v.PostContent)
			}
		}

		if len(contents) == 0 {
			return errors.New(fmt.Sprintf("DeferredInquireAiMq.execService content empty err, invalid param: %+v", message))
		}

		// logx.Infof("DeferredInquireAiMq.execService AskDeepSeekAI : %+v ", contents)

		aiResp, err := deepseek.AskDeepSeekAI(contents, globalkey.DeepseekContentTypeDialogue)
		if err != nil {
			logx.Infow("DeferredInquireAiMq.execService AskDeepSeekAI err", logx.Field("detail", err.Error()))
			return err
		}

		// logx.Infof("DeferredInquireAiMq.execService AskDeepSeekAI : %+v ", aiResp)

		// map[choices:[map[finish_reason:stop index:0 logprobs:\u003cnil\u003e message:map[content:推荐几款清新如刚洗完白衬衫的香水：\n\n1. **Maison Margiela Replica Lazy Sunday Morning** - 这款香水以清新的铃兰和麝香为主调，营造出慵懒周末早晨的氛围。\n2. **Clean Warm Cotton** - 如其名，这款香水捕捉了温暖棉质衣物的舒适感，带有柑橘和花香。\n3. **Byredo Blanche** - 这是一款极简主义的香水，融合了醛类、玫瑰和白麝香，创造出干净而优雅的气息。\n\n这些香水都能带来如同刚洗过的白衬衫般的清新感觉。 role:assistant]]] created:1.74039417e+09 id:6339476a-9eb2-461d-a27d-5067905a9312 model:deepseek-chat object:chat.completion system_fingerprint:fp_3a5770e1b4_prod usage:map[completion_tokens:124 prompt_cache_hit_tokens:0 prompt_cache_miss_tokens:31 prompt_tokens:31 prompt_tokens_details:map[cached_tokens:0] total_tokens:155]]

		// map[choices:[map[finish_reason:stop index:0 logprobs:\u003cnil\u003e message:map[content:推荐几款清新如刚洗完白衬衫的香水：\n\n1. **Maison Margiela Replica Lazy Sunday Morning** - 铃兰和麝香，带来干净舒适感。\n2. **Clean Reserve Warm Cotton** - 柑橘与花香，宛如阳光晒过的棉布。\n3. **Byredo Blanche** - 醛香与玫瑰、檀木结合，纯净而优雅。\n\n这些香水都能营造出清新自然的氛围，适合约会使用。 role:assistant]]] created:1.740393111e+09 id:9f3ed07b-72bc-40e8-92c0-d385dc191a5c model:deepseek-chat object:chat.completion system_fingerprint:fp_3a5770e1b4_prod usage:map[completion_tokens:96 prompt_cache_hit_tokens:0 prompt_cache_miss_tokens:31 prompt_tokens:31 prompt_tokens_details:map[cached_tokens:0] total_tokens:127]]

		// map[choices:[map[
		//       finish_reason:stop
		//       index:0
		//       logprobs:<nil>
		//       message:map[
		//         content:4711的经典古龙水（Original Eau de Cologne）是最受欢迎的选择，以其清新的柑橘和草本香调著称，适合日常使用。如果你喜欢更独特的气味，可以尝试4711 Acqua Colonia系列中的其他款式，如“血橙与罗勒”或“粉红胡椒与葡萄柚”，它们提供了不同的香气体验。
		//         role:assistant
		//       ]
		//     ]
		//   ]
		//   created:1.739009715e+09
		//   id:da9f1d11-803c-488c-a205-b40a06b4beba
		//   model:deepseek-chat
		//   object:chat.completion
		//   system_fingerprint:fp_3a5770e1b4
		//   usage:map[
		//     completion_tokens:74
		//     prompt_cache_hit_tokens:0
		//     prompt_cache_miss_tokens:30
		//     prompt_tokens:30
		//     prompt_tokens_details:map[cached_tokens:0]
		//     total_tokens:104
		//   ]
		// ]
		//结果添加forum_post
		if choices, ok := aiResp["choices"]; ok {
			for _, choice := range choices.([]any) {
				if msg, ok := choice.(map[string]any)["message"]; ok {
					var messageMap = msg.(map[string]any)
					var content, role string
					if c, ok := messageMap["content"]; ok {
						content = c.(string)
					}
					if r, ok := messageMap["role"]; ok {
						role = r.(string)
					}

					if len(content) > 0 && len(role) > 0 {
						_, err = l.svcCtx.ForumRpc.CreatePosts(l.ctx, &forumclient.PostsInfo{
							ForumId:         pointy.GetPointer(uint64(l.svcCtx.Config.Query.DSForumId)),
							TopicId:         message.TopicId,
							AuthorId:        pointy.GetPointer(uint64(l.svcCtx.Config.Query.DSUserId)),
							AuthorNickname:  pointy.GetPointer(l.svcCtx.Config.Query.DSUserName),
							AuthorAvatar:    pointy.GetPointer(l.svcCtx.Config.Query.DSUserAvatar),
							PostTitle:       pointy.GetPointer(strings.TrimSpace(role)),
							PostContent:     pointy.GetPointer(strings.TrimSpace(content)),
							Status:          pointy.GetPointer(uint32(globalkey.StatusDraft)),
							AuthorAnonymous: pointy.GetPointer(uint32(1)),
						})
						if err != nil {
							logx.Infow("DeferredInquireAiMq.execService CreatePosts err", logx.Field("detail", err.Error()))
							return err
						}

						m := mqueuex.DeferredInquireAIMessage{
							UserId:         message.UserId,
							TopicId:        message.TopicId,
							Type:           pointy.GetPointer(globalkey.ChatMessageTypeSysDSAnswerStored),
							Content:        pointy.GetPointer(content),
							AuthorId:       pointy.GetPointer(uint64(l.svcCtx.Config.Query.DSUserId)),
							AuthorNickname: pointy.GetPointer(l.svcCtx.Config.Query.DSUserName),
							AuthorAvatar:   pointy.GetPointer(l.svcCtx.Config.Query.DSUserAvatar),
						}
						card := l.analyzePerfumeName(content, *message.UserId)
						if len(card.List) > 0 {
							for _, v := range card.List {
								m.PerfumeCard = append(m.PerfumeCard, &mqueuex.CardInfo{
									Uid:      v.Uid,
									Id:       v.Id,
									Type:     v.Type,
									LinkUrl:  v.LinkUrl,
									Title:    v.Title,
									PicUrl:   v.PicUrl,
									Subtitle: v.Subtitle,
									Label:    v.Label,
									Price:    v.Price,
								})
							}
						}
						body, err := json.Marshal(m)
						if err != nil {
							logx.Errorw("DeferredInquireAiMq.execService json.Marshal error", logx.Field("detail", err.Error()))
						} else {
							websocket.SendMessage(
								l.svcCtx.Config.WebSocketChatUrl,
								string(body),
								strconv.FormatUint(*message.UserId, 10),
							)
						}
					}
				}
			}
		}
	}
	return nil
}

// 解析名称并查询百科
func (l *DeferredInquireAiMq) analyzePerfumeName(content string, userId uint64) *forumclient.CardListResp {
	//1、es分词
	analyzeRequest := map[string]any{
		"text":     content,
		"analyzer": "ik_max_word",
	}

	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(analyzeRequest); err != nil {
		logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewEncoder Error encoding analyze request: %+v", err)
		return nil
	}

	res, err := l.svcCtx.EsClient.Indices.Analyze(
		l.svcCtx.EsClient.Indices.Analyze.WithContext(l.ctx),
		l.svcCtx.EsClient.Indices.Analyze.WithBody(&buf),
	)
	if err != nil {
		logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewEncoder Error encoding analyze request: %s+v", err)
		return nil
	}
	defer res.Body.Close()

	// 解析并打印结果
	var resp map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
		logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewDecoder Error: %+v", err)
		return nil
	}

	var entrys []string
	if len(resp) > 0 {
		if len(resp) > 0 {
			if tokens, ok := resp["tokens"]; ok {
				if len(tokens.([]any)) > 0 {
					for _, token := range tokens.([]any) {
						if t, tok := token.(map[string]any)["token"]; tok {
							if len(strings.TrimSpace(t.(string))) > 0 {
								entrys = append(entrys, t.(string))
							}
						}
					}
				}
			}
		}
	}
	//和brand.dic文件中的结果对比，取出有用的分词,提高精确度
	var newEntry []string
	if len(entrys) > 0 {
		fileContent, err := os.ReadFile("temp/brand.dic")
		if err != nil {
			logx.Errorf("DeferredInquireAiMq analyzePerfumeName ReadFile Error: %+v", err)
			return nil
		}
		/*
			content:
					圣安纽莉塔
					艾克卡帕
					萨满德·奇拉士
					爱马仕花园
					佩枪朱丽叶
					帕尔马之水
			contentStr: *圣安纽莉塔*艾克卡帕*萨满德·奇拉士*爱马仕花园*佩枪朱丽叶*帕尔马之水*

			可成功:*爱马仕花园*  *佩枪朱丽叶*  *帕尔马之水*
			不可成功: *花园*  *朱丽叶*  *水*
			这样设计避免多次循环造成性能损耗，防止分词中含有各别词语匹配成功
		*/
		contentStr := "*" + strings.Replace(string(fileContent), "\r\n", "*", -1) + "*"
		for _, entry := range entrys {
			if strings.Contains(contentStr, "*"+entry+"*") {
				newEntry = append(newEntry, entry)
			}
		}
	}

	var pid []string
	var pidMap = make(map[string]struct{})
	if len(newEntry) > 0 {
		for _, v := range newEntry {
			var entryBuf bytes.Buffer
			query := map[string]any{
				"query": map[string]any{
					"bool": map[string]any{
						"must": map[string]any{
							"multi_match": map[string]any{
								"query":     v,
								"fields":    []string{"Title", "Slug"},
								"type":      "best_fields",
								"fuzziness": "AUTO",
							},
						},
					},
				},
			}

			if err := json.NewEncoder(&entryBuf).Encode(query); err != nil {
				logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewEncoder Error: %+v", err)
				return nil
			}

			// 执行搜索请求
			esResp, err := l.svcCtx.EsClient.Search(
				l.svcCtx.EsClient.Search.WithContext(l.ctx),
				l.svcCtx.EsClient.Search.WithIndex("scentrobe-kb-entry"),
				l.svcCtx.EsClient.Search.WithBody(&buf),
				l.svcCtx.EsClient.Search.WithTrackTotalHits(true),
				l.svcCtx.EsClient.Search.WithPretty(),
			)
			if err != nil {
				logx.Errorf("DeferredInquireAiMq analyzePerfumeName EsClient.Search Error: %+v", err)
				return nil
			}

			defer res.Body.Close()
			if res.IsError() {
				var e map[string]any
				if err = json.NewDecoder(res.Body).Decode(&e); err != nil {
					logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewDecoder Error: %+v", err)
					return nil
				}
			}

			// logrus.Info(fmt.Sprintf("DownloadAsExcel res: %+v", res))

			var r map[string]any
			if err := json.NewDecoder(esResp.Body).Decode(&r); err != nil {
				logx.Errorf("DeferredInquireAiMq analyzePerfumeName NewDecoder Error: %+v", err)
				return nil
			}

			hits := r["hits"].(map[string]any)["hits"].([]any)
			if len(hits) > 0 {
				for _, v := range hits {
					entryId := int(v.(map[string]any)["_source"].(map[string]any)["Id"].(float64))
					if entryId > 0 {
						pidStr := strconv.FormatInt(int64(entryId), 10)
						if _, ok := pidMap[pidStr]; !ok {
							pid = append(pid, pidStr)
							pidMap[pidStr] = struct{}{}
						}
					}
				}
			}
		}
	}
	return l.getCardList(pid, userId)
}

func (l *DeferredInquireAiMq) getCardList(pid []string, userId uint64) *forumclient.CardListResp {
	preload := "forumCard:Id,PostId,ObjectId,ObjectType,LinkUrl,PicUrl,Title,Subtitle,Label,Price"
	eagerLoad := "forumCard:"
	var filters []string
	filters = append(filters, "PostId,in:"+strings.Join(pid, ","))
	filters = append(filters, "ObjectType,equalTo:"+strconv.FormatInt(int64(globalkey.ForumCardTypePerfume), 10))
	var platformId uint32 = globalkey.ThirdPartyPlatformWechatMini
	card, err := l.svcCtx.ForumRpc.GetCardList(l.ctx, &forumclient.CardListReq{
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		logx.Errorf("DeferredInquireAiMq getCardList GetCardList Error: %+v", err)
		return nil
	}
	return card
}
